package com.gss.plugin.mp.mybatisplus;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.gss.plugin.mp.config.MpProperties;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

/**
 * @author: DYang
 * @since: 2023/8/22
 * @description:
 */
@Configuration
@MapperScanner(basePackages = {"${stars.mp.mybatis-plus.mapper-locations}"})
@EnableTransactionManagement // 开启事务管理
public class MybatisPlusConfig {

    @Autowired
    private DataSource dataSource;
    @Autowired
    private MpProperties mpProperties;
    @Autowired
    private MybatisPlusProperties mybatisPlusProperties;
    @Autowired
    private MybatisPlusFillHandler mybatisPlusFillHandler;
    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public SqlSessionFactory sqlSessionFactory(ObjectProvider<List<Interceptor>> plugins) throws Exception {
        MpProperties.MybatisPlus mybatisPlus = mpProperties.getMybatisPlus();
        //全局配置
        GlobalConfig globalConfig = mybatisPlusProperties.getGlobalConfig();
        globalConfig.setMetaObjectHandler(mybatisPlusFillHandler);

        GlobalConfig.DbConfig dbConfig = mybatisPlusProperties.getGlobalConfig().getDbConfig();
        dbConfig.setInsertStrategy(mybatisPlus.getDbInsertStrategy());
        dbConfig.setUpdateStrategy(mybatisPlus.getDbUpdateStrategy());
        dbConfig.setWhereStrategy(mybatisPlus.getDbWhereStrategy());
        dbConfig.setIdType(mybatisPlus.getIdType());

        // configuration配置
        MybatisConfiguration configuration = mybatisPlusProperties.getConfiguration();
        if (configuration == null) {
            configuration = new MybatisConfiguration();
        }
        configuration.setMapUnderscoreToCamelCase(mybatisPlus.isMapUnderscoreToCamelCase());
        configuration.setLogImpl(mybatisPlus.getLogImpl());

        mybatisPlusProperties.setMapperLocations(mybatisPlus.getMapperLocations());

        MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
        sqlSessionFactory.setDataSource(dataSource);
        sqlSessionFactory.setGlobalConfig(globalConfig);

        sqlSessionFactory.setPlugins(plugins.getIfAvailable().toArray(new Interceptor[0]));
        return sqlSessionFactory.getObject();
    }


    /**
     * 检查spring容器里是否有对应的bean,有则进行消费
     *
     * @param clazz    class
     * @param consumer 消费
     * @param <T>      泛型
     */
    private <T> void getBeanThen(Class<T> clazz, Consumer<T> consumer) {
        if (applicationContext.getBeanNamesForType(clazz, false, false).length > 0) {
            consumer.accept(applicationContext.getBean(clazz));
        }
    }

    /**
     * 检查spring容器里是否有对应的bean,有则进行消费
     *
     * @param clazz    class
     * @param consumer 消费
     * @param <T>      泛型
     */
    private <T> void getBeansThen(Class<T> clazz, Consumer<List<T>> consumer) {
        if (applicationContext.getBeanNamesForType(clazz, false, false).length > 0) {
            final Map<String, T> beansOfType = applicationContext.getBeansOfType(clazz);
            List<T> clazzList = new ArrayList<>();
            beansOfType.forEach((k, v) -> clazzList.add(v));
            consumer.accept(clazzList);
        }
    }

    @Bean
    public DataSourceTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

//    @Bean
//    public PaginationInnerInterceptor paginationInnerInterceptor() {
//
////        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//        // 添加分页插件
//        PaginationInnerInterceptor pageInterceptor = new PaginationInnerInterceptor();
//        // 设置请求的页面大于最大页后操作，true调回到首页，false继续请求。默认false
//        pageInterceptor.setOverflow(false);
//        // 单页分页条数限制，默认无限制
//        pageInterceptor.setMaxLimit(500L);
//        // 设置数据库类型
//        pageInterceptor.setDbType(DbType.POSTGRE_SQL);
//
////        interceptor.addInnerInterceptor(pageInterceptor);
////        return interceptor;
//        return pageInterceptor;
//    }

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        // 向MyBatis-Plus的过滤器链中添加分页拦截器，需要设置数据库类型（主要用于分页方言）
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL));
//        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        // 添加乐观锁拦截器
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }



}
